package org.ccay.validator.impl;

import java.util.HashMap;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import org.ccay.core.exception.ApplicationException;
import org.ccay.core.log.ILogger;
import org.ccay.registry.util.RegistryQueryUtil;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.validator.ValidatorApplicationException;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.validator.ActionValidatorManager;

/**
 * DefaultValidationInterceptor
 * 
 * Implements the aopalliance method interceptor. Validate service class method.
 * 
 * @author chaowangbang
 * 
 */
public class DefaultValidationInterceptor extends DataValidationInterceptor implements MethodInterceptor, ApplicationContextAware {
	
	/** 日志类 */
	private final ILogger logger = CcayLoggerFactory.getLogger(DefaultValidationInterceptor.class);
	
	/**
	 * Gets the current action and its context and delegates to
	 * {@link ActionValidatorManager} proper validate method.
	 * 
	 * @param invocation
	 *            the execution state of the Action.
	 * @throws Exception
	 *             if an error occurs validating the action.
	 */
	protected void doBeforeInvoke(final MethodInvocation invocation) throws ApplicationException {
		Object service = invocation.getThis();

		// the action name has to be from the url, otherwise validators that use
		// aliases, like
		// MyActio-someaction-validator.xml will not be found, see WW-3194
		String method = invocation.getMethod().getName();

        // Setting this so that other classes, like object factories, can use the ActionProxy and other
        // contextual information to operate
		ActionContext.setContext(new ActionContext(new HashMap<String, Object>()));
		ActionContext actionContext = ActionContext.getContext();
    	ValueStack valueStack = createValueStack();
        actionContext.setValueStack(valueStack);
        
        // 验证参数的合法性
        validateArgument(invocation, service, method);
	} 

	/**
	 * 验证参数的合法性
	 * 
	 * @param invocation
	 * @param action
	 * @param method
	 * @param context
	 * @throws ValidatorApplicationException
	 */
	private void validateArgument(final MethodInvocation invocation, Object action, String method) throws ValidatorApplicationException {
		String context = "";
		logger.debug("Validating " + context + " with method " + method + ".");
		
		Object[] arguments = invocation.getArguments();
    	
    	// 构造验证上下文
    	DefaultValidatorContext validatorContext = createValidatorContext();
		for (int i = 0; i < arguments.length; i ++ ) {
	    	// 定义目标对象
			Object bean = arguments[i];
	    	// 设置参数的索引
	    	validatorContext.setParam("argIndex", String.valueOf(i));
	    	// 设置方法的名字
	    	validatorContext.setParam("methodName", method);
	    	// 设置验证目标对象
	    	validatorContext.setParam("validatorTarget", bean);
	    	// 设置业务对象
	    	validatorContext.setParam("serviceClass", action);
	    	
	    	try {
	    		if(actionValidatorManager != null){
	    			// 执行验证方法
	    			actionValidatorManager.validate(action, context, validatorContext, method);
	    		}
	    	} catch (Exception e) {
	    		logger.error(e);
	    		throw new ValidatorApplicationException(EX_VALIDATION_UNKNOWN, e);
	    	}
		}
    	// 取出验证信息
    	processValidateResult(validatorContext);
	}

	/* （非 Javadoc）
	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
	 */
	public Object invoke(final MethodInvocation invocation) throws Throwable {
		//允许全局禁用
		if(!RegistryQueryUtil.getBooleanValue("Ccay.GlobalParamters.DisableServerValidation")){
			doBeforeInvoke(invocation);
		}
		 
		return invocation.proceed();
	}

	/* （非 Javadoc）
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	public void setApplicationContext(ApplicationContext ctx) throws BeansException {
		// 从验证容器中取出验证管理器
		ActionValidatorManager actionValidatorManager = DefaultValidatorManager.createInstance(ctx);
		this.setActionValidatorManager(actionValidatorManager);
	}
}
